/* 
    使用建造者模式来建造日志器，而不要让用户直接去构造日志器，简化用户的使用复杂度 
        1. 抽象一个日志器建造者类
            1. 设置日志器类型
            2. 将不同类型日志器的创建放到同一个日志器建造者类中完成
*/

#ifndef __M_LOGBUILD__H__
#define __M_LOGBUILD__H__

#include "util.hpp"
#include "level.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include "format.hpp"
#include "logger.hpp"
#include <unordered_map>

namespace Log
{
    enum LoggerType
    {
        LOGGER_SYNC = 0, // 同步
        LOGGER_ASYNC     // 异步
    };

    class LoggerBuild
    {
    public:
        using ptr = std::shared_ptr<LoggerBuild>;
        LoggerBuild()
            : _logger_type(LOGGER_SYNC), _level(Log::LogLevel::Value::DEBUG), _loop_type(AsyncType::ASYNC_SAFE)
        {
        }
        void BuildLoggerType(LoggerType loggertype)
        {
            _logger_type = loggertype;
        }
        void BuildEnableAsyncUnsafe()
        {
            _loop_type = AsyncType::ASYNC_UNSAFE;
        }
        void BuildLoggerName(std::string loggername)
        {
            _logger_name = loggername;
        }
        void BuildLogLevel(LogLevel::Value level)
        {
            _level = level;
        }
        void BuildFormatter(std::string fmt)
        {
            _formatter = std::make_shared<Formatter>(fmt);
        }
        // SinkType：落地方式
        // ...Args：传入的不定参数
        template <class SinkType, class... Args>
        void BuildLogSink(Args &&...args)
        {
            auto sink = std::make_shared<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }
        virtual Logger::ptr Build() = 0;

    protected:
        std::string _logger_name;         // 日志器名称
        LoggerType _logger_type;          // 日志器类型
        LogLevel::Value _level;           // 日志等级
        Formatter::ptr _formatter;        // 控制格式化
        std::vector<LogSink::prt> _sinks; // 日志的落地方式
        AsyncType _loop_type;             // 异步日志器的状态
    };

    // 2. 派生出具体的建造者类 —— 局部日志器的建造者
    class LocalLoggerBuild : public LoggerBuild
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_logger_name.empty());

            // get:返回其管理的原始指针
            if (!_formatter.get())
            {
                _formatter = std::make_shared<Formatter>();
            }

            if (_sinks.empty())
            {
                BuildLogSink<StdoutSink>();
            }

            if (_logger_type == LOGGER_ASYNC)
            {
                // std::cout << "LocalLoggerBuild: 构造默认是异步的" << std::endl;
                // std::cout << "日志器名称：" << _logger_name << std::endl;
                return std::make_shared<AsyncLogger>(_logger_name, _level, _formatter, _sinks, _loop_type);
            }

            // std::cout << "LocalLoggerBuild: 构造默认是同步的" << std::endl;
            // std::cout << "日志器名称：" << _logger_name << std::endl;
            return std::make_shared<SyncLogger>(_logger_name, _level, _formatter, _sinks);
        }
    };

    // 日志器管理:使用单例模式对日志器进行管理
    class LoggerManager
    {
    public:
        static LoggerManager& getInstance()
        {
            // 在C++11之后，针对静态局部变量，编译器在编译的层面实现了线程安全
            // 当静态局部变量在没有构造完成之前，其它的线程进入就会阻塞
            static LoggerManager eton;
            return eton;
        }
        // 添加日志器
        void addLogger(Logger::ptr& logger)
        {
            if(hasLogger(logger->name()))
                return;
            
            std::unique_lock<std::mutex>lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(),logger));
        }
        // 判断该日志器是否存在
        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
                return false;
            
            return true;
        }
        // 返回获取的日志器
        Logger::ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
                return Logger::ptr();

            return it->second;
        }
        // 返回默认日志器
        Logger::ptr rootLogger()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _root_logger;
        }
    private:
        LoggerManager()
        {
            std::unique_ptr<Log::LoggerBuild> builder(new Log::LocalLoggerBuild());
            builder->BuildLoggerName("root");
            _root_logger = builder->Build();
            _loggers.insert(std::make_pair("root",_root_logger));
        }
    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;   // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };

    // 3. 派生出具体的建造者类 —— 全局的日志器建造者
    class GlobalLoggerBuild : public LoggerBuild
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_logger_name.empty());

            // get:返回其管理的原始指针
            if (!_formatter.get())
            {
                _formatter = std::make_shared<Formatter>();
            }

            if (_sinks.empty())
            {
                BuildLogSink<StdoutSink>();
            }

            Logger::ptr logger;
            if (_logger_type == LOGGER_ASYNC)
            {
                logger = std::make_shared<AsyncLogger>(_logger_name, _level, _formatter, _sinks, _loop_type);
                // std::cout << "GlobalLoggerBuild: 异步日志器" << std::endl;
                // std::cout << "日志器名称：" << _logger_name << std::endl;
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _level, _formatter, _sinks);
                // std::cout << "GlobalLoggerBuild: 同步日志器" << std::endl;
                // std::cout << "日志器名称：" << _logger_name << std::endl;
            }

            LoggerManager::getInstance().addLogger(logger);
            // std::cout << "日志器名称：" << logger->name() << std::endl;

            return logger;
        }
    };
}

#endif